home *** CD-ROM | disk | FTP | other *** search
- ;;; Remarks
- ;;; =======
- ;;;
- ;;; * This code relies on XPK_MARGIN being >= 32 !!!
- ;;; If only one Bit in the last ControlWord is used, the remaining 15
- ;;; will be filled with 0. This will result in 15 LiteralItems on
- ;;; decompression. Additionaly there is NO CHECK, whether a match
- ;;; matches more than the input. This can result in a match which is
- ;;; 17 Bytes to long giving a maximum total of 32 Bytes garbled after
- ;;; the outputblock after decompresion.
- ;;; (XPK_MARGIN is 256 in xpkmaster.library V2.0)
-
- ; XDEF compress_fast
-
- ;On entry:
- ; a0 = InBuf
- ; a1 = OutBuf
- ; a2 = HashTab
- ; d0 = InLen
-
- ;We only test if we have compressed all the input after we already have
- ;compressed all the data belonging to a group. A group is the data encoded
- ;using one controlword. Therefor it could happen, that we compress 16*18
- ;bytes to much, garbling inocent memory on decompression and compressing
- ;too much data. To prevent this (doing too much work is always a bad thing(tm))
- ;we compress the data with two different abortion strategies:
- ;1st we only test for completion after compressing all the data belonging
- ;to one group. This test fails, if there are fewer than a safetymargin bytes
- ;to compress. We then switch to the second safer but slower method
- ;of testing after each controlbit.
-
- SAFETYMARGIN = 16*18
-
- compress_fast:
- movem.l a3-a6/d1-d7,-(sp)
- move.l a1,-(sp) ;push OutBuf for total length calculation
- move.l d0,d5 ;d5:=InLen
-
- ;Fill the Hash with pointers to the end
- ;of the input. So we never ever get a
- ;valid Hashentry by chance, but only
- ;if we stored it there.
-
- move.l a1,d7
- add.l d0,d7 ;d7:=OutBuf+InLen
- and.b #$fc,d7 ;align d7 to long (for wordstreammove at end)
- move.l d7,a4 ;a4:=OutBuf+InLen
- add.l a0,d5 ;d5:=InBuf+InLen
-
- move.l a2,a6 ;a6:=Hash
- move.w #2048-1,d0 ;Hashsize=2^(11+3+2) = 2^16 Bytes
- fillHashLoop:
- move.l d5,(a6)+
- move.l d5,(a6)+
- move.l d5,(a6)+
- move.l d5,(a6)+
- move.l d5,(a6)+
- move.l d5,(a6)+
- move.l d5,(a6)+
- move.l d5,(a6)+
- dbra d0,fillHashLoop
-
- sub.l #SAFETYMARGIN,d5 ;d5:=InBuf+InLen-SAFETYMARGIN
-
- lea NewControlWord(pc),a3
- move.l #4095,d4 ;d4:=Const:4095
- moveq.l #0,d1 ;upper word has to be 0
-
- bra.s StartMainLoop
-
- ;REGISTER MAP
- ;============
-
- ; a0 Points to the next input byte.
- ; a1 Points to the next literal output byte.
- ; a2 Points to the hash table.
- ; a3 Pointer to NewControlWord/SafeControl code.
- ; a4 Points to the word output stream.
- ; a5 Points to place to put control word in output.
- ; a6 Temporary.
- ; a7 Stack pointer. Don't touch!
-
- ; d0 Temporary
- ; d1 Temporary
- ; d2 Counter of Controlbits to insert into the control word.
- ; d3 Buffers the current control word.
- ; d4 Constant 4095 for rangecheck.
- ; d5 Points to the byte after the input block.
- ; d6 Second level controlbit counter used in the safe loop.
- ; d7 Points to the byte after the output block.
-
- ;;;---------------------------------------------------------------------------
-
- COPYN MACRO
- IFGE \1-10
- addq.w #18-\1,d0
- ENDC
- IFLT \1-10
- add.w #18-\1,d0
- ENDC
- dbra d2,MatchFinish ;End of loop.
- jmp MatchExitOfs(a3); control word is full.
- ENDM
-
- ;=====================================================================
-
- ;SAFE COMPRESSION LOOP
- ;=====================
- ;This loopcontrol part fools the main compression part into thinking
- ;The control word is allways full. The main part thus calls us each
- ;time it has filled a bit into the control word. This enables us to
- ;check for completion and overrun after each compressed item.
-
- ;There's no need to check for overruns!
- ;An overrun occurs if the TOTAL size of the literal bytes and
- ;the control words and the copyinfo TOGETHER do exceed the size
- ;of the input. Even in the worst case the literal byte stream or
- ;the control words and the copyinfo together do not exceed
- ;the size of the outbuf. Therefore the overruncheck can safely be
- ;postponed to the end.
-
- EnterSafeLoop:
- lea SafeControl(pc),a3 ;redirect jumps to NewControlWord.
- add.l #SAFETYMARGIN,d5 ;d5:=InBuf+InLen
- bra.s StartSafeMainLoop
-
- ;===============================
-
- subq.l #1,a0 ; = These two instructions have to be identical
- move.w d0,-(a4) ; = to the two before NewControlWord!!!
- SafeControl: ;Jump here every iteration to test for end.
-
- cmp.l a0,d5 ;Input bytes left=d5-a0
- bls end_compress_loop ;Loop ends if no more input bytes.
-
- dbra d6,NextRound ;control word isn't full, do next.
-
- move.w d3,(a5) ;Write control word.
- StartSafeMainLoop:
- subq.l #2,a4
- move.l a4,a5 ;Next output word is control word.
-
- moveq #15,d6 ;Reinitialize control bits counter
- moveq #-1,d3 ;Fill new control word with $ffff
- NextRound:
- moveq #0,d2 ;Clear control bit counter to fool
- ;the others into thinking it is full
- ;so we get called
- bra.s CompressLoop
-
- ;===================================================================
-
- ;FAST COMPRESSION LOOP
- ;=====================
-
- MatchExit: ;undo the effect on a0 of the last
- subq.l #1,a0 ;failing cmp.b (a6)+,(a0)+
- MatchExit_18:
- move.w d0,-(a4) ;Write the CopyItemInformation
-
- NewControlWord: ;Jump here every 16 iterations to set up a new control word.
-
- MatchExitOfs = MatchExit-NewControlWord
- MatchExit18Ofs = MatchExit_18-NewControlWord
-
- move.w d3,(a5) ;Write control word.
- StartMainLoop:
- cmp.l a0,d5 ;reached the safetymargin ?
- bls.s EnterSafeLoop ;Fast Loop ends if to few input bytes.
- subq.l #2,a4
- move.l a4,a5 ;Next output word is control word.
- moveq #15,d2 ;Reinitialize control bits counter
- moveq #-1,d3 ;Fill new control word with $ffff
- bra.s CompressLoop
-
- ;=====================================================================
- ;placed here to be within bra.s range, could be anywhere
-
- do_literal_1:
- move.b -1(a0),(a1)+ ;Copy the literal byte to the output.
- add.w d3,d3 ;Inject a 0 (literal) into control buffer.
- dbra d2,CompressLoop ;End of loop.
- jmp (a3) ; control word is full.
-
- do_literal_2:
- subq.l #2,a0
- move.b (a0)+,(a1)+ ;Copy the literal byte to the output.
- add.w d3,d3 ;Inject a 0 (literal) into control buffer.
- dbra d2,CompressLoop ;End of loop.
- jmp (a3) ; control word is full.
-
- do_literal_3:
- subq.l #3,a0
- do_literal:
- move.b (a0)+,(a1)+ ;Copy the literal byte to the output.
- add.w d3,d3 ;Inject a 0 (literal) into control buffer.
- dbra d2,CompressLoop ;End of loop.
- jmp (a3) ; control word is full.
-
- do_copy_3: COPYN 3
- do_copy_4: COPYN 4
- do_copy_5: COPYN 5
- ;=====================================================================
-
- MatchFinish:
- subq.l #1,a0 ;Undo effect of last cmp.b (a6)+,(a0)+
- MatchFinish_18:
- move.w d0,-(a4) ;Write the CopyItemInformation
- ;-----------------------------------------
- ;CALCULATE HASH TABLE ENTRY FOR KEY IN ZIV
- ;-----------------------------------------
- CompressLoop:
- move.l a0,a6 ;d1:=hashtable entry for
- move.b (a6)+,d1 ;(a0), 1(a0) and 2(a0)
- lsl.w #3,d1
- add.b (a6)+,d1
- lsl.w #3,d1
- add.b (a6),d1
- lsl.w #2,d1
-
- move.l 0(a2,d1.l),a6 ;Place the hash table entry into a6.
- move.l a0,d0 ;Calculate the entry's offset from src pos.
- sub.l a6,d0 ;d0 := a0-entry
- move.l a0,0(a2,d1.l) ;Replace hash entry by current source address
- cmp.l d4,d0 ;Is the Hashentry more than 4095 Bytes away?
- bhi.s do_literal
-
- COMPARE_BYTE MACRO
- cmp.b (a6)+,(a0)+
- bne \1
- ENDM
-
- COMPARE_BYTE do_literal_1 ;Look if there is a match of at least
- COMPARE_BYTE do_literal_2 ;length 3.
- COMPARE_BYTE do_literal_3
-
- asl.w #4,d0 ;Shift Offset to make room for lengthinfo
- rol.w #1,d3 ;Inject a 1 (copy) into control buffer.
- ;since we definitely are doing a copy.
-
- COMPARE_BYTE do_copy_3 ;determine the length of the match
- COMPARE_BYTE do_copy_4
- COMPARE_BYTE do_copy_5
- COMPARE_BYTE do_copy_6
- COMPARE_BYTE do_copy_7
- COMPARE_BYTE do_copy_8
- COMPARE_BYTE do_copy_9
- COMPARE_BYTE do_copy_10
- COMPARE_BYTE do_copy_11
- COMPARE_BYTE do_copy_12
- COMPARE_BYTE do_copy_13
- COMPARE_BYTE do_copy_14
- COMPARE_BYTE do_copy_15
- COMPARE_BYTE do_copy_16
- COMPARE_BYTE do_copy_17
-
- do_copy_18: ;Match length is 18 Bytes.
- dbra d2,MatchFinish_18 ;End of loop.
- jmp MatchExit18Ofs(a3) ;control word is full.
-
- do_copy_6: COPYN 6
- do_copy_7: COPYN 7
- do_copy_8: COPYN 8
- do_copy_9: COPYN 9
- do_copy_10: COPYN 10
- do_copy_11: COPYN 11
- do_copy_12: COPYN 12
- do_copy_13: COPYN 13
- do_copy_14: COPYN 14
- do_copy_15: COPYN 15
- do_copy_16: COPYN 16
- do_copy_17: COPYN 17
-
- ;;;The main loop ends here.
- ;;;---------------------------------------------------------------------------
- ;FINALIZATION
- ;============
-
- end_compress_loop: ;Fill the rest of the control word
- lsl.w d6,d3 ;with 0. [0 means literal items]
- move.w d3,(a5) ;Write it to its output position
-
- ;Copy the wordstream after the literals pointed to by a1.
- move.l a4,d0 ;d0:=Number of Bytes to increase a1
- sub.l a1,d0 ;till a1 and a4 are equally aligned.
- bcs.s overrun ;byte- and wordstream together exceede the
- ;size of the output buffer.
- moveq #3,d1
- and.w d0,d1
-
- moveq.l #0,d0 ;pad a1 up to make a1 and a4 equally aligned.
- bra.s EFLoop
- FLoop: move.b d0,(a1)+
- EFLoop: dbra d1,FLoop
-
- sub.l a4,d7 ;d7:=size of wordstream
-
- lsr.l #2,d7
- bcc.s NoWord
- move.w (a4)+,(a1)+
- NoWord: lsr.l #1,d7
- bcc.s NoLong
- move.l (a4)+,(a1)+
- NoLong: lsr.l #1,d7
- bcc.s NoQuad
- move.l (a4)+,(a1)+
- move.l (a4)+,(a1)+
- NoQuad: lsr.l #1,d7
- bcc.s ECLoop
- bra.s MCLoop
-
- CLoopH: swap d7
- CLoop: move.l (a4)+,(a1)+
- move.l (a4)+,(a1)+
- move.l (a4)+,(a1)+
- move.l (a4)+,(a1)+
- MCLoop: move.l (a4)+,(a1)+
- move.l (a4)+,(a1)+
- move.l (a4)+,(a1)+
- move.l (a4)+,(a1)+
- ECLoop: dbra d7,CLoop
- swap d7
- dbra d7,CLoopH
-
- move.l (sp)+,a0 ;Pop OutBuf
- move.l a1,d0
- sub.l a0,d0 ;d0:=Final output length
- endcompress:
- movem.l (sp)+,a3-a6/d1-d7
- rts
-
- ;OVERRUN PROCESSING
- ;==================
- ;This is the place to jump when an overrun occurs.
- ;When an overrun occurs we can drop everything we are doing
- overrun:
- moveq.l #0,d0
- addq.l #4,sp ;pop OutBuf.
- bra.s endcompress
-